use crate::json::listener;

pub trait Listener {
    fn enter_null_node(&mut self, token: &Token);
    fn enter_string_node(&mut self, token: &Token);
    fn enter_number_node(&mut self, token: &Token);
    fn enter_identifier_node(&mut self, token: &Token);
    fn enter_true_node(&mut self, token: &Token);
    fn enter_false_node(&mut self, token: &Token);
    fn enter_comment_node(&mut self, token: &Token);
    fn enter_object_node(&mut self, token: &Token);
    fn exit_object_node(&mut self, token: &Token);
    fn enter_array_node(&mut self, token: &Token);
    fn exit_array_node(&mut self, token: &Token);
    fn enter_comma_node(&mut self, token: &Token);
    fn enter_colon_node(&mut self, token: &Token);
    // fn get_value(&mut self) -> String;
    fn get_value(&self) -> &String;
}

const EOF: char = 0 as char;

enum TOKEN {
    /**
     * 空串
     */
    EOF,

    /**
     * null值
     */
    Null,
    /**
     * true值
     */
    True,
    /**
     * false值
     */
    False,

    Number,
    //字符串
    String,
    //逗号
    Comma,
    //分号
    Colon,
    //中括号
    ArrLeft,
    ArrRight,
    //大括号
    ObjLeft,
    ObjRight,

    //扩展语法-支持Javascript对象格式的属性名
    ID,
    Comment,
}

pub struct Token {
    token: TOKEN,
    pub value: String,
    row_idx: u32,
    col_idx: u32,
}

pub struct Lexer {
    chars: Vec<char>,
    pos: usize,
    length: usize,
    row_idx: u32,
    col_idx: u32,
    token: Token,
    pub value: String,
}

impl Lexer {
    pub fn new(json_str: &String) -> Lexer {
        let mut char_vec: Vec<char> = vec![];
        for chr in json_str.chars() {
            char_vec.push(chr);
        }
        let len = char_vec.len();
        println!("chars.len:{}", char_vec.len());
        Lexer {
            chars: char_vec,
            pos: 0,
            length: len,
            row_idx: 0,
            col_idx: 0,
            token: Token {
                token: TOKEN::EOF,
                value: "".to_string(),
                row_idx: 0,
                col_idx: 0,
            },
            value: "".to_string(),
        }
    }

    fn next(&mut self) -> char {
        self.pos = self.pos + 1;
        self.current()
    }

    fn current(&self) -> char {
        if self.pos >= self.length {
            EOF
        } else {
            *self.chars.get(self.pos).unwrap()
        }
    }

    fn curr_token(&self) -> &Token {
        &self.token
    }

    fn next_token(&mut self) -> &Token {
        loop {
            self.skip_space();
            let ch = self.current();
            self.token = match ch {
                '"' => self.read_string(),
                EOF => self.read_eof(),
                '/' => self.read_comment(),
                '{' => self.read_obj_left(),
                '}' => self.read_obj_right(),
                '[' => self.read_arr_left(),
                ']' => self.read_arr_right(),
                ',' => self.read_comma(),
                ':' => self.read_colon(),
                '0'..='9' | '+' | '-' | '.' => self.read_number(),
                'a'..='z' | 'A'..='Z' | '_' => self.read_identifier(),
                _ => panic!("不能识别的字符'{}',当前位置:({},{})", ch, self.row_idx, self.col_idx)
            };
            //如果遇到注释,跳过
            match self.token.token {
                TOKEN::Comment => (),
                _ => break
            }
        }
        return &self.token;
    }

    fn skip_space(&mut self) {
        loop {
            let ch = self.current();
            match ch {
                '\n' => self.read_newline(),
                '\r' | '\t' | ' ' => self.read_empty(),
                _ => break
            }
        }
    }

    fn read_number(&mut self) -> Token {
        let start = self.pos;
        //尝试读取符号
        let mut ch = self.current();
        if ch == '-' || ch == '+' {
            ch = self.next();
        }
        //尝试读取纯数字
        let mut num_count = 0;
        while ch >= '0' && ch <= '9' {
            ch = self.next();
            num_count += 1;
        }
        //尝试读取小数
        if ch == '.' {
            loop {
                ch = self.next();
                if ch >= '0' && ch <= '9' {
                    num_count += 1;
                } else {
                    break;
                }
            }
        }
        if num_count == 0 {
            panic!("数值格式错误，数字长度为零,位置:{}", self.row_idx)
        }
        if ch == 'L' {
            //长整形
            self.next();
        } else if ch == 'F' {
            //单精度浮点
            self.next();
            //isFloat = true
        } else if ch == 'D' {
            //双精度浮点
            self.next();
        } else if ch == 'e' || ch == 'E' {
            //科学计数法
            ch = self.next();
            if ch == '+' || ch == '-' {
                ch = self.next();
            }
            while ch >= '0' && ch <= '9' {
                ch = self.next()
            }
            if ch == 'D' || ch == 'F' {
                self.next();
            }
        }
        if self.pos - start == 0 {
            panic!("数值长度为空,位置:{}", self.row_idx)
        }
        let mut value = String::new();
        for i in start..self.pos {
            //todo:为啥这里要写*才能通过编译？
            value.push(*self.chars.get(i).unwrap());
        }
        Token {
            token: TOKEN::Number,
            value,
            row_idx: self.row_idx,
            col_idx: self.col_idx,
        }
    }

    fn read_string(&mut self) -> Token {
        //TODO:待完善
        let mut escapes: [char; 128] = [' '; 128];
        escapes['t' as usize] = '\t';
        escapes['n' as usize] = '\n';
        escapes['r' as usize] = '\r';
        escapes['\\' as usize] = '\\';
        escapes['/' as usize] = '/';

        let mut str_value = String::new();
        loop {
            self.next();
            let mut ch = self.current();
            if ch == '"' {
                self.next();
                break;
            }
            if ch == '\\' {
                self.next();
                ch = self.current();
                if escapes.len() > ch as usize && escapes[ch as usize] as i32 != 0 {
                    let next = escapes[self.current() as usize];
                    str_value.push(next)
                } else if ch == 'x' {
                    panic!("TODO")
                } else if ch == 'u' {
                    panic!("TODO")
                } else {
                    str_value.push('\\');
                    str_value.push(ch)
                }
            } else if ch == EOF {
                panic!("内容已经匹配完,仍然没有匹配到期望的字符:当前位置:{}", self.row_idx);
            } else {
                str_value.push(ch)
            }
        }
        Token {
            token: TOKEN::String,
            value: str_value,
            row_idx: self.row_idx,
            col_idx: self.col_idx,
        }
    }


    fn read_identifier(&mut self) -> Token {
        let mut identifier = String::new();
        identifier.push(self.current());
        loop {
            let ch = self.next();
            match ch {
                'a'..='z' | 'A'..='Z' | '_' | '0'..='9' => identifier.push(ch),
                _ => break
            }
        }

        let kind: TOKEN;
        match identifier.as_str() {
            "null" => kind = TOKEN::Null,
            "true" => kind = TOKEN::True,
            "false" => kind = TOKEN::False,
            _ => kind = TOKEN::ID,
        }

        Token {
            token: kind,
            value: identifier,
            row_idx: self.row_idx,
            col_idx: self.col_idx,
        }
    }

    fn read_comment(&mut self) -> Token {
        let mut comment = String::new();
        self.next();
        if self.current() != '/' {
            panic!("无法识别的字符:{},期望出现的是:/,当前位置:{}", self.current(), self.row_idx);
        }
        loop {
            self.next();
            let ch = self.current();
            if ch == '\n' {
                self.next();
                break;
            }
            comment.push(ch);
        }
        Token {
            token: TOKEN::Comment,
            value: comment,
            row_idx: self.row_idx,
            col_idx: self.col_idx,
        }
    }

    fn read_obj_left(&mut self) -> Token {
        let col_idx = self.col_idx;
        let row_idx = self.row_idx;
        self.next();
        Token {
            token: TOKEN::ObjLeft,
            value: "{".to_string(),
            row_idx,
            col_idx,
        }
    }
    fn read_obj_right(&mut self) -> Token {
        let col_idx = self.col_idx;
        let row_idx = self.row_idx;
        self.next();
        Token {
            token: TOKEN::ObjRight,
            value: "}".to_string(),
            row_idx,
            col_idx,
        }
    }

    fn read_arr_left(&mut self) -> Token {
        let col_idx = self.col_idx;
        let row_idx = self.row_idx;
        self.next();
        Token {
            token: TOKEN::ArrLeft,
            value: "[".to_string(),
            row_idx,
            col_idx,
        }
    }
    fn read_arr_right(&mut self) -> Token {
        let col_idx = self.col_idx;
        let row_idx = self.row_idx;
        self.next();
        Token {
            token: TOKEN::ArrRight,
            value: "]".to_string(),
            row_idx,
            col_idx,
        }
    }
    fn read_comma(&mut self) -> Token {
        let col_idx = self.col_idx;
        let row_idx = self.row_idx;
        self.next();
        Token {
            token: TOKEN::Comma,
            value: ",".to_string(),
            row_idx,
            col_idx,
        }
    }
    fn read_colon(&mut self) -> Token {
        let col_idx = self.col_idx;
        let row_idx = self.row_idx;
        self.next();
        Token {
            token: TOKEN::Colon,
            value: ":".to_string(),
            row_idx,
            col_idx,
        }
    }

    fn read_eof(&mut self) -> Token {
        Token {
            token: TOKEN::EOF,
            value: "".to_string(),
            row_idx: self.row_idx,
            col_idx: self.col_idx,
        }
    }

    fn read_newline(&mut self) {
        self.row_idx += 1;
        self.col_idx = 1;
        self.next();
    }

    fn read_empty(&mut self) {
        self.next();
    }
}

pub struct JSON {
    lexer: Lexer,
    listener: Box<dyn Listener>,
}

impl JSON {
    fn new(listener: Box<dyn Listener>, json: &String) -> JSON {
        return JSON {
            lexer: Lexer::new(json),
            listener,
        };
    }

    pub fn pretty(str: &String) -> String {
        return JSON::format_json(str, true);
    }
    pub fn compress(str: &String) -> String {
        return JSON::format_json(str, false);
    }

    fn format_json(str: &String, pretty: bool) -> String {
        let listener = Box::new(listener::FormatListener {
            builder: "".to_string(),
            pretty,
            scope: 0,
            line_start: false,
        });
        let mut json = JSON::new(listener, str);
        json.lexer.next_token();
        json.parse_json();
        json.get_value().to_string()
    }

    pub fn get_value(&self) -> &String {
        self.listener.get_value()
    }

    fn parse_json(&mut self) {
        let token = self.lexer.curr_token();
        match token.token {
            TOKEN::ObjLeft => self.parse_object(),
            TOKEN::ArrLeft => self.parse_array(),
            TOKEN::Null => self.listener.enter_null_node(token),
            TOKEN::True => self.listener.enter_true_node(token),
            TOKEN::False => self.listener.enter_false_node(token),
            TOKEN::Number => self.listener.enter_number_node(token),
            TOKEN::String => self.listener.enter_string_node(token),
            TOKEN::Comment => self.listener.enter_comment_node(token),
            _ => raise_panic("未知的字符", token)
        }
    }

    fn parse_object(&mut self) {
        let token = self.lexer.curr_token();
        self.listener.enter_object_node(token);
        //属性数量
        let mut prop_count = 0;
        loop {
            let mut token = self.lexer.next_token();

            //匹配对象是否关闭
            match token.token {
                TOKEN::ObjRight => break,
                TOKEN::EOF => raise_panic("解析对象,期望的是“:”,解析已结束", &token),
                _ => ()
            }

            //匹配属性之间的逗号
            if prop_count > 0 {
                //匹配属性之间的分隔符
                match token.token {
                    TOKEN::Comma => self.listener.enter_comma_node(&token),
                    _ => raise_panic("解析对象,期望的是“:”", &token)
                }
                token = self.lexer.next_token()
            }

            //匹配对象属性Key
            match token.token {
                TOKEN::ID => self.listener.enter_identifier_node(&token),
                TOKEN::String => self.listener.enter_string_node(&token),
                _ => raise_panic("解析对象,期望的是属性名", &token),
            }
            token = self.lexer.next_token();
            prop_count = prop_count + 1;

            //匹配中间的冒号
            match token.token {
                TOKEN::Colon => self.listener.enter_colon_node(&token),
                _ => raise_panic("解析对象,期望的是“:”", &token)
            }
            self.lexer.next_token();

            //匹配属性值，可以是任意的JSON
            self.parse_json()
        }
        self.listener.exit_object_node(self.lexer.curr_token())
    }

    fn parse_array(&mut self) {
        self.listener.enter_array_node(self.lexer.curr_token());

        let mut element_count = 0;
        loop {
            let token = self.lexer.next_token();
            //判断数组是否关闭
            match token.token {
                TOKEN::ArrRight => break,
                _ => ()
            }

            //匹配元素之间的逗号
            if element_count > 0 {
                match token.token {
                    TOKEN::Comma => self.listener.enter_comma_node(&token),
                    _ => raise_panic("解析数组,期望的是“,”", &token)
                }
                self.lexer.next_token();
            }

            //匹配数组元素
            self.parse_json();
            element_count = element_count + 1;
        }
        self.listener.exit_array_node(self.lexer.curr_token())
    }
}

fn raise_panic(message: &str, token: &Token) {
    panic!("{},当前字符:“{}”,当前位置:({},{})", message, token.value, token.row_idx, token.col_idx)
}